package com.zhong.media.media.player;

import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;

import com.zhong.media.media.listener.OnPlayerCallback;

import java.util.List;
import java.util.Map;

/**
 * <pre>
 *     author: Zhong
 *     time  : 2020/3/11
 *     desc  : 播放器实现类，封装了通用的操作方法、状态监听
 *              支持切换SurfaceView和TextureView
 * </pre>
 */
public class ZVideoPlayer extends RelativeLayout implements IVideoPlayer {
    private static final String TAG = ZVideoPlayer.class.getSimpleName();

    public static final int SURFACE_VIEW_TYPE = 1;
    public static final int TEXTURE_VIEW_TYPE = 2;

    // all possible internal states
    private static final int STATE_ERROR = -1;              //错误
    private static final int STATE_IDLE = 0;                //空闲
    private static final int STATE_PREPARED = 2;            //准备完成
    private static final int STATE_PLAYING = 3;             //播放中
    private static final int STATE_PAUSED = 4;              //暂停
    private static final int STATE_PLAYBACK_COMPLETED = 5;  //播放完成
    private static final int STATE_STOP = 6;       //停止

    private static final int DEFAULT_RETRY_COUNT = 5;       //默认重试次数
    private static final int RETRY_DURATION = 500;    //重试间隔时间

    // settable by the client
    private Uri mUri;
    private Map<String, String> mHeaders;

    private int videoIndex = 0;
    private List<String> videoPathList;

    //是否循环播放视频
    private boolean isLoopPlay = false;
    //播放器状态
    private int mCurrentState = STATE_IDLE;

    //播放器类型
    private int playerType = SURFACE_VIEW_TYPE;

    //回调监听
    private OnPlayerCallback onPlayerCallback;

    private Context context;
    private IPlayer player;

    //最大重试次数
    private int maxRetryCount = DEFAULT_RETRY_COUNT;
    //已重试次数
    private int retryCount = 0;

    public ZVideoPlayer(Context context) {
        this(context, null);
    }

    public ZVideoPlayer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ZVideoPlayer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        this.context = context;

//        initPlayer(context);
    }

    /**
     * 初始化播放器
     * @param context
     */
    private void initPlayer(Context context){
        //TODO 逻辑待完善
        if(playerType == SURFACE_VIEW_TYPE){
            player = new MySurfaceView(context);
        } else{
            player = new MyTextureView(context);
        }

        addView((View) player, getChildCount());
    }

    /**
     * 播放器类型，SurfaceView or TextureView
     * @param playerType
     */
    public void setPlayerType(int playerType){
        if(playerType != SURFACE_VIEW_TYPE && playerType != TEXTURE_VIEW_TYPE){
            Log.d(TAG,"请设置正确的播放器类型");
            return;
        }

        this.playerType = playerType;
    }

    @Override
    public void setVideoPath(String videoPath) {
        setVideoURI(Uri.parse(videoPath));
    }

    @Override
    public void setVideoURI(Uri uri) {
        setVideoURI(uri, null);
    }

    @Override
    public void setVideoURI(Uri uri, Map<String, String> headers) {
        mUri = uri;
        mHeaders = headers;

        startVideo();
    }

    @Override
    public void setVideoPathList(List<String> videoPathList) {
        this.videoPathList = videoPathList;

        if(videoPathList != null && videoPathList.size() > 0){
            setVideoPath(videoPathList.get(0));
        }
    }

    /**
     * 设置最大重试次数
     * @param maxRetryCount
     */
    public void setMaxRetryCount(int maxRetryCount){
        if(maxRetryCount < 0){
            return;
        }

        this.maxRetryCount = maxRetryCount;
    }

    /**
     * 播放index
     * @param index
     */
    private void playVideoListIndex(int index){
        if(videoPathList == null || videoPathList.size() <= 0){
            Log.d(TAG, "Video list is null");
            return;
        }

        if(index < 0 || index >= videoPathList.size()){
            Log.d(TAG, "The index is out of array");
            return;
        }

        setVideoPath(videoPathList.get(index));
        this.videoIndex = index;
    }

    /**
     * 设置是否循环播放
     * @param isLoopPlay
     */
    public void setIsLoopPlay(boolean isLoopPlay){
        this.isLoopPlay = isLoopPlay;
    }

    @Override
    public void setOnPlayerCallback(OnPlayerCallback onPlayerCallback) {
        this.onPlayerCallback = onPlayerCallback;
    }

    /**
     * 注册监听
     */
    private void registerListener(MediaPlayer mMediaPlayer) {
        if(mMediaPlayer == null){
            Log.d(TAG, "This mediaPlayer is null");
            return;
        }

        player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                Log.d(TAG, "onPrepared");
                mCurrentState = STATE_PREPARED;

                if( onPlayerCallback != null){
                    onPlayerCallback.onVideoStart(mUri, videoIndex);
                    //隐藏loading
                    onPlayerCallback.onLoadingChanged(false);
                }
            }
        });

        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer arg0) {
                Log.d(TAG, "onCompletion");
                if(null != onPlayerCallback){
                    onPlayerCallback.onVideoComplete(mUri, videoIndex);
                }

                playControl();
            }
        });

        mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {

            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                Log.d(TAG, "onError--WHAT--" + what + "extra--" + extra);
                mCurrentState = STATE_ERROR;

                if(onPlayerCallback != null){
                    onPlayerCallback.onVideoError(mUri, videoIndex);
                }

                errorRetry();
                return true;
            }
        });

        mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {

            @Override
            public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
                Log.d(TAG, "VideoPlayer--onVideoSizeChanged");
            }
        });

        mMediaPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
            @Override
            public boolean onInfo(MediaPlayer mp, int what, int extra) {
                Log.d(TAG, "onInfo");
                switch (what) {
                    case MediaPlayer.MEDIA_INFO_BUFFERING_START:// 播放开始卡顿
                        if(onPlayerCallback != null){
                            onPlayerCallback.onLoadingChanged(true);
                        }
                        break;
                    case MediaPlayer.MEDIA_INFO_BUFFERING_END:// 播放卡顿结束
                        if(onPlayerCallback != null){
                            onPlayerCallback.onLoadingChanged(false);
                        }
                        break;
                }
                return false;
            }
        });
    }

    /**
     * 播放控制
     */
    void playControl(){
        if(videoPathList != null && videoPathList.size() > 0){
            if(videoIndex < videoPathList.size() - 1){
                playVideoListIndex(++videoIndex);
            } else{
                if(isLoopPlay){
                    playVideoListIndex(0);
                }
            }
        } else{
            if(isLoopPlay){
                setVideoURI(mUri);
            }
        }
    }

    /**
     * 报错重试
     */
    void errorRetry(){
        Log.d(TAG, "播放异常" + RETRY_DURATION + "毫秒后重试：retryCount =" + retryCount
                + "  maxRetryCount = " + maxRetryCount);
        if(retryCount < maxRetryCount){
            removeCallbacks(retryRunnable);
            postDelayed(retryRunnable,RETRY_DURATION);

            retryCount++;
        } else{
            removeCallbacks(retryRunnable);
            releasePlayer();

            if(onPlayerCallback != null){
                onPlayerCallback.onVideoStop(retryCount, mUri, videoIndex);
            }
        }
    }

    Runnable retryRunnable = new Runnable() {
        @Override
        public void run() {
            setVideoURI(mUri);
        }
    };

    @Override
    public void startVideo() {
        if(player == null){
            initPlayer(context);
        }

        try{
            player.setVideoURI(mUri, mHeaders);

            registerListener(player.getMediaPlayer());
        } catch (NullPointerException e){
            e.printStackTrace();
            //播放异常，重试处理
            errorRetry();
        }
    }

    /**
     * Stop video
     */
    @Override
    public void stopVideo() {
        if(player != null){
            player.stop();
            mCurrentState = STATE_STOP;
        }
    }

    /**
     * Pause video
     */
    @Override
    public void pauseVideo() {
        if(player != null){
            if(player.isPlaying()){
                player.pause();

                mCurrentState = STATE_PAUSED;
            } else{
                player.start();
                mCurrentState = STATE_PLAYING;
            }
        }
    }

    /**
     * release MediaPlayer
     */
    @Override
    public void releasePlayer(){
        try {
            removeCallbacks(retryRunnable);

            if (player != null) {
                player.release();
                player = null;
                mCurrentState = STATE_STOP;
                retryCount = 0;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void fullScreen() {

    }

    @Override
    public void fullScreen(boolean isFullScreen) {

    }

}
